import * as jose from 'jose'
import {nanoid} from 'nanoid'
import { getServerEnv } from './env';
import logger from './logger';

const MAX_AGE_HOURS = 24 * 30

const SECRET = Buffer.from(getServerEnv('JWT_SECRET'), "base64");
const ISSUER = getServerEnv('JWT_ISSUER');

export async function createJwt(userId: bigint): Promise<{jwt:string, maxAge: number}> {
  try {
    const jwt =  await new jose.SignJWT({})
      .setProtectedHeader({alg: 'HS512',})
      .setIssuedAt()
      .setIssuer(ISSUER)
      .setSubject(userId + "")
      .setJti(nanoid())
      .setExpirationTime(MAX_AGE_HOURS+ "h")
      .sign(SECRET)
    return { jwt, maxAge: MAX_AGE_HOURS }
  } catch(err) {
    logger.error("[createJwt] failed", err)
    throw err
  }
}

type JwtVerifyResult = { ok: true; userId: bigint; sessionId: string } | { ok: false; message: string };

export async function verifyJwt(jwt: string): Promise<JwtVerifyResult> {
  try {
    const { payload } = await jose.jwtVerify(jwt, SECRET, { issuer: ISSUER });
    if (!payload.jti) {
      // log.error("jwt has no jti: %s", { jwt, payload });
      return { ok: false, message: "token has no jti" };
    }
    const jti = payload.jti;

    if (!payload.sub) {
      // log.error("jwt has no sub: %s", { jwt, payload });
      return { ok: false, message: "token has no sub" };
    }
    const userId = BigInt(payload.sub);

    return { ok: true, userId, sessionId: jti };
  } catch (err) {
    // log.error("jwt verify failed", err);
    return { ok: false, message: "unhandled error when jwt verifying" };
  }
}

export async function decodeJwt(jwt: string): Promise<jose.JWTPayload> {
  return await jose.decodeJwt(jwt)
}